/**
 *数字的五行分别是：
 * 　　1为阳木、2为阴木。3为阳火、4为阴火。5为阳土、6为阴土。
 * 　　7为阳金、8为阴金。9为阳水、0为阴水。
 * 　　1与6的组合为水；2与7的组合为火；3与8的组合为木；4与9的组合为金；0与5的组合为土。
 * 通常选择车牌号数字的时候，可以依据车主五行喜忌来选择车牌号码，
 * 例如，如果说车主命主五行喜金，一般情况就宜用7或8或49或94作车牌号。
 * 如果车主命主五行忌火，一般情况就不宜用3或4或27或72作车牌号。
 */
package org.longteng.core.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 易经数理工具类
 * @author hymn.com
 */
@Slf4j
public class ChineseYijingNumUtil {

    /**
     * 根据（易经）中华五格81计算号码数理
     * <br>公式为：(手机号码最后四位÷80-商的整数)×80=K
     * @param mobilePhoneNum
     * @return
     */
    public static int yijingNumberCalculate(String mobilePhoneNum) {
        int result = 0;
        // 字符串中提取数字
        String numberStr = StringExUtils.truckNotNumber(mobilePhoneNum);

        String mobileR4 = StringUtils.right(numberStr,4);
        BigDecimal mobileR4int = new BigDecimal(mobileR4);
        BigDecimal baseNum80 = new BigDecimal(80);
        // 返回数组中包含两个元素，第一个元素为两数相除的商，第二个元素为余数
        BigDecimal mobileR4Step1 = mobileR4int.divide(baseNum80);
        log.debug("号码{}后四位{}除80为：{},参考N/80={}", mobilePhoneNum,mobileR4int, mobileR4Step1,mobileR4int.floatValue()/baseNum80.floatValue());
        // 整数部分
        BigDecimal integerPart = mobileR4Step1.setScale(0, RoundingMode.DOWN);
        // 小数部分
        BigDecimal fractionalPart = mobileR4Step1.subtract(integerPart);
        // ×80=K
        BigDecimal mobileR4Step2 = fractionalPart.multiply(baseNum80);
        result = mobileR4Step2.intValue();
        log.debug("号码{}后四位{}商{}-整数部分得{}*80为K：{}",mobilePhoneNum,mobileR4int,mobileR4Step1,fractionalPart,mobileR4Step2);

        return result;
    }

    /**
     * 号码三才得配
     * 谓三才得配是指天、地、人三者的关系要处理恰当，人生活在天地之间，一定要尊天敬地。如果三位数，其中间数不要全大于前后的数，如果四位数字，其中间两位数不要全大于前后的数，如果五位数，其中间的一位数不要全大于两边的数
     * @return
     */
    public static String talent3Str(char[] cartNumArr) {
        if(cartNumArr != null && cartNumArr.length>=3) {
            int idx = cartNumArr.length/2;
            boolean gtFront  = talentGtFront(cartNumArr, idx);
            boolean gtBehind = talentGtBehind(cartNumArr, idx);
            if (gtFront && gtBehind) {
                log.debug("码三才得配,中间数字'{}'全大于前合数字.", cartNumArr[idx]);
                return "三才得配:凶";
            } else {
                return "三才得配:吉";
            }
        } else {
            return "";
        }
    }

    /**
     * 是否全大于前面
     * @param cartNumArr
     * @return
     */
    private static boolean talentGtFront(char[] cartNumArr, int idx) {
        boolean gtFront = true;
        if ((cartNumArr.length & 1) == 0) { // 偶数就取中间2位
            for (int i = 0; i < idx - 1; i++) {
                if (cartNumArr[i] >= cartNumArr[idx] || cartNumArr[i] >= cartNumArr[idx-1]) {
                    gtFront = false;
                    break;
                }
            }
        } else {
            for (int i = 0; i < idx; i++) {
                if (cartNumArr[i] >= cartNumArr[idx]) {
                    gtFront = false;
                    break;
                }
            }
        }
        return gtFront;
    }

    /**
     * 是否全大于后面
     * @param cartNumArr
     * @param idx
     * @return
     */
    private static boolean talentGtBehind(char[] cartNumArr, int idx) {
        boolean gtBehind = true;
        if ((cartNumArr.length & 1) == 0) { // 偶数就取中间2位
            for (int i = idx + 1; i < cartNumArr.length; i++) {
                if (cartNumArr[i] >= cartNumArr[idx] || cartNumArr[i] >= cartNumArr[idx-1]) {
                    gtBehind = false;
                    break;
                }
            }
        } else {
            for (int i = idx + 1; i < cartNumArr.length; i++) {
                if (cartNumArr[i] >= cartNumArr[idx]) {
                    gtBehind = false;
                    break;
                }
            }
        }
        return gtBehind;
    }

    /**
     * 解析号码有五行的含意，即1、6为水、2、7为火、3、8为木、4、9为金、5、0为土。
     * 有方位的含意，即1、6为北方、2、7为南方、3、8为东方、4、9为西方、5、0为居中
     * @param numStr
     * @return
     */
    public static String parseWuXingCountStr(String numStr) {
        WuXingEnum.M.parseMatchCount(numStr);
        StringBuilder wuXingCountStrBuf = new StringBuilder();
        wuXingCountStrBuf.append(WuXingEnum.S.parseMatchCount(numStr))
                .append(WuXingEnum.H.parseMatchCount(numStr))
                .append(WuXingEnum.M.parseMatchCount(numStr))
                .append(WuXingEnum.J.parseMatchCount(numStr))
                .append(WuXingEnum.T.parseMatchCount(numStr))
                ;
        return wuXingCountStrBuf.toString();
    }

    /**
     * 列出五行统计说明。解析号码有五行的含意，即1、6为水、2、7为火、3、8为木、4、9为金、5、0为土
     * @param numStr
     * @return 如：水:1木:2:1
     */
    public static String parseWuXingCountDescStr(String numStr) {
        WuXingEnum.M.parseMatchCount(numStr);
        StringBuilder wuXingCountStrBuf = new StringBuilder();
        wuXingCountStrBuf.append(WuXingEnum.S.parseCountFortuneStr(numStr))
                .append(WuXingEnum.H.parseCountFortuneStr(numStr))
                .append(WuXingEnum.M.parseCountFortuneStr(numStr))
                .append(WuXingEnum.J.parseCountFortuneStr(numStr))
                .append(WuXingEnum.T.parseCountFortuneStr(numStr))
        ;
        return wuXingCountStrBuf.toString();
    }

    /**
     * 五行定义
     * 1为阳木、2为阴木。3为阳火、4为阴火。5为阳土、6为阴土。
     * 7为阳金、8为阴金。9为阳水、0为阴水
     * 1与6的组合为水；2与7的组合为火；3与8的组合为木；4与9的组合为金；0与5的组合为土。
     */
    public enum WuXingEnum {
        S("水","16,61,0,9"),H("火","27,72,3,5"),M("木","38,83,1,2")
        ,J("金","49,94,7,8"),T("土","50,05,5,6");

        // 成员变量
        private String name;
        private int count = 0;
        private String[] matchnum;
        // 构造方法
        private WuXingEnum(String name, String matchnums) {
            this.name = name;
            this.matchnum = matchnums.split(",");
        }

        /**
         * 解析有多少个匹配数字
         * @param numStr
         * @return
         */
        public int parseMatchCount(String numStr) {
            if(this.count >0 ) {
                return this.count;
            }
            for (String c : matchnum) {
                int charCount = StringUtils.countMatches(numStr, c);
                this.count += charCount;
            }
            return this.count;
        }

        /**
         * 解析有多少个匹配数字结果，有值返回，无则返回""
         * @param numStr
         * @return
         */
        public String parseCountFortuneStr(String numStr) {
            int charCount = this.parseMatchCount(numStr);
            if(charCount >0 ) {
                return StringExUtils.format("{}{}", this.count,this.name);
            } else {
                return "";
            }
        }
    }
}
